package com.slipper.common.util;

import com.slipper.common.constants.Constants;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;

public class HttpUtil {
    private static final Logger logger = LoggerFactory.getLogger(HttpUtil.class);

    /**
     * POST请求
     * @param url url
     * @param header header参数
     * @param body body参数
     * @param charset 字符编码
     */
    public static String doPost(
            String url,
            Map<String, Object> header,
            Map<String, Object> body,
            String charset) {
        String result = null;
        try {
            URL actionUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) actionUrl.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Content-Type", "application/json");
            if (header != null) {
                header.forEach((key, value) -> conn.setRequestProperty(key, String.valueOf(value)));
            }
            conn.connect();
            DataOutputStream out = new DataOutputStream(conn.getOutputStream());
            out.write(StringUtil.toBytes(GsonUtil.toJson(body), charset));
            out.flush();
            out.close();

            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
            try {
                String line = reader.readLine();
                while(line != null) {
                    buffer.append(line);
                    line = reader.readLine();
                }
            } catch(Exception e) {
                logger.error("", e);
            } finally {
                try {
                    reader.close();
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
            result = buffer.toString();
            conn.disconnect();
        } catch(Exception e) {
            logger.error("请求出错: " + url
                    + ", charset: " + charset
                    + ", header: " + GsonUtil.toJson(header)
                    + ", body: " + GsonUtil.toJson(body)
                    + ", result: " + result, e);
            throw new RuntimeException(e);
        } finally {
            logger.info("HttpService post url: " + url
                + ", charset: " + charset
                + ", header: " + GsonUtil.toJson(header)
                + ", body: " + GsonUtil.toJson(body)
                + ", result: " + result);
        }
        return result;
    }

    /**
     * POST请求
     * @param url url
     * @param body body参数
     * @param header header参数
     * @param charset 字符编码
     */
    public static String doPost(
            String url,
            String body,
            Map<String, String> header,
            String charset) {
        String result = null;
        try {
            URL actionUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) actionUrl.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Content-Type", "application/json");
            if (header != null) {
                header.forEach(conn::setRequestProperty);
            }
            conn.connect();
            DataOutputStream out = new DataOutputStream(conn.getOutputStream());
            out.write(StringUtil.toBytes(body, charset));
            out.flush();
            out.close();

            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
            try {
                String line = reader.readLine();
                while(line != null) {
                    buffer.append(line);
                    line = reader.readLine();
                }
            } catch(Exception e) {
                logger.error("", e);
            } finally {
                try {
                    reader.close();
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
            result = buffer.toString();
            conn.disconnect();
        } catch(Exception e) {
            logger.error("请求出错: " + url
                    + ", charset: " + charset
                    + ", header: " + GsonUtil.toJson(header)
                    + ", body: " + body
                    + ", result: " + result, e);
            throw new RuntimeException(e);
        } finally {
            logger.info("HttpService post url: " + url
                    + ", charset: " + charset
                    + ", header: " + GsonUtil.toJson(header)
                    + ", body: " + body
                    + ", result: " + result);
        }
        return result;
    }

    public static String doPost(String url) {
        return doPost(url, null, Constants.UTF_8, null);
    }

    public static String doPost(String url, Map<String, String> header) {
        return doPost(url, null, Constants.UTF_8, header);
    }

    public static String doPost(String url, String charset) {
        return doPost(url, null, charset, null);
    }

    public static String doPost(String url, String charset, Map<String, Object> data) {
        return doPost(url, data, charset, null);
    }

    public static String doPost(String url, Map<String, Object> data, String charset, Map<String, String> header) {
        String result = null;
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            RequestConfig config = RequestConfig.custom().setSocketTimeout(15000).build();
            httpPost.setConfig(config);

            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            httpPost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
            httpPost.setHeader("Accept-Encoding", "gzip, deflate, sdch");
            httpPost.setHeader("Accept-Language", "zh-CN,zh;q=0.8");
            httpPost.setHeader("Upgrade-Insecure-Requests", "1");
            httpPost.setHeader("Connection", "keep-alive");
            httpPost.setHeader("Cache-Control", "max-age=0");

            if (header != null) {
                header.forEach(httpPost::addHeader);
            }

            if (data != null && !data.isEmpty()) {
                List<NameValuePair> params = new ArrayList<>();
                for (Map.Entry<String, Object> entry : data.entrySet()) {
                    params.add(new BasicNameValuePair(entry.getKey(),
                            entry.getValue() == null ? null : entry.getValue().toString()));
                }
                httpPost.setEntity(new UrlEncodedFormEntity(params, charset));
            }
            CloseableHttpResponse response = httpClient.execute(httpPost);
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, charset);
                    logger.debug("请求url：{}，数据：{}，返回数据：{}", url, data, result);
                }
            }
        } catch (Exception e) {
            logger.error("请求url：" + url + "，数据：" + data + "，出错！", e);
        }
        return result;
    }

    public static Map<String, String> parseParam(HttpServletRequest request) {
        Map<String, String> reqMap = new LinkedHashMap<>();
        Enumeration<String> enum1 = request.getParameterNames();
        while (enum1.hasMoreElements()) {
            String paramName = enum1.nextElement();
            String paramValue = request.getParameter(paramName);
            reqMap.put(paramName, paramValue);
        }
        return reqMap;
    }

    public static String readBody(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    logger.error("", e);
                }
            }
        }
    }

    public static String addParam(String url, String key, String value) {
        if (url == null) {
            url = "";
        }

        StringBuilder builder = new StringBuilder(url);
        if (builder.indexOf("?") < 0) {
            builder.append("?").append(key).append("=").append(value);
        } else {
            builder.append("&").append(key).append("=").append(value);
        }
        return builder.toString();
    }

    public static String doGet(String url, String charset, Map<String, Object> data) throws Exception {
        logger.info("HttpService get url: " + url + ", charset: " + charset + ", data: " + data);
        StringBuilder buf = new StringBuilder(url);
        if(data != null && !data.isEmpty()) {
            if(buf.indexOf("?") < 0) {
                buf.append("?_nomean_=somemean");
            }
            for(Map.Entry<String, Object> entry : data.entrySet()) {
                if(entry != null && entry.getValue() != null) {
                    buf.append("&");
                    buf.append(entry.getKey());
                    buf.append("=");
                    buf.append(URLEncoder.encode(entry.getValue().toString(), charset));
                }
            }
        }
        URL actionUrl = new URL(buf.toString());
        HttpURLConnection conn = (HttpURLConnection) actionUrl.openConnection();
        conn.setUseCaches(false);
        conn.connect();
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
        try {
            String line = reader.readLine();
            while(line != null) {
                buffer.append(line);
                line = reader.readLine();
            }
        } catch(Exception e) {
            logger.error("", e);
        } finally {
            try {
                reader.close();
            } catch (Exception e) {
                logger.error("", e);
            }
        }
        conn.disconnect();
        String result = buffer.toString();
        logger.info("HttpService get result: " + result);
        return result;
    }

    public static String doGet(String url, Map<String, String> param) {

        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }

            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);
            // if (StringExt.isNotEmpty(token)) {
            //     httpGet.addHeader("Authorization", token);
            // }
            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            logger.error("", e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                logger.error("", e);
            }
        }
        return resultString;
    }

    public static String doPostJson(String url, String charset, String data) throws Exception {
        return doPostJson(url, charset, data, null);
    }

    public static String doPostJson(String url, String charset, String data, String authHeader) throws Exception {
        String result = null;
        try {
            URL actionUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) actionUrl.openConnection();
            if (authHeader != null && !authHeader.isEmpty()) {
                conn.setRequestProperty("Authorization", authHeader);
            }
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            conn.setUseCaches(false);
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.connect();
            DataOutputStream out = new DataOutputStream(conn.getOutputStream());
            out.write(data.getBytes(charset));
            out.flush();
            out.close();

            StringBuilder buffer = new StringBuilder();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
            try {
                String line = reader.readLine();
                while(line != null) {
                    buffer.append(line);
                    line = reader.readLine();
                }
            } catch(Exception e) {
                logger.error("", e);
            } finally {
                try {
                    reader.close();
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
            result = buffer.toString();
            conn.disconnect();
        } finally {
            logger.info("HttpService post url: " + url
                + ", charset: " + charset
                + ", data: " + data
                + ", authHeader: " + authHeader
                + ", result: " + result);
        }
        return result;
    }

    public static boolean isMultipartContent(HttpServletRequest request) {
        if (!"POST".equalsIgnoreCase(request.getMethod())) {
            return false;
        }

        String contentType = request.getContentType();
        if (contentType == null) {
            return false;
        } else {
            return contentType.toLowerCase(Locale.ENGLISH).startsWith("multipart/");
        }
    }

    public static Map<String, String> doPostJson(
            String url,
            String json,
            Map<String, String> header,
            List<String> headerList) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            RequestConfig config = RequestConfig.custom().setSocketTimeout(15000).build();
            httpPost.setConfig(config);

            if (header != null) {
                header.forEach(httpPost::addHeader);
            }
            StringEntity stringEntity = new StringEntity(json, "utf-8");
            httpPost.setEntity(stringEntity);

            CloseableHttpResponse response = httpClient.execute(httpPost);
            if (response == null) {
                return null;
            }
            HttpEntity resEntity = response.getEntity();
            if (resEntity == null) {
                return null;
            }
            String body = EntityUtils.toString(resEntity, "utf-8");
            logger.debug("请求url：{}，数据：{}，返回数据：{}", url, json, body);

            Map<String, String> result = new HashMap<>();
            result.put("body", body);
            if (!headerList.isEmpty()) {
                headerList.forEach(headerName -> result.put(headerName, response.getLastHeader(headerName).getValue()));
            }

            return result;
        } catch (Exception e) {
            logger.error("请求url：" + url + "，数据：" + json + "，出错！", e);
        }
        return null;
    }
}
